using System;
using System.Collections.Generic;
using System.Text;
using Mpi.Common.Collections;
using System.ComponentModel;
using Xeml.Document.Contracts;
using System.Collections.ObjectModel;

namespace Xeml.Document.EnvironmentalOntology
{
    public class XeoTerm : IDynamicOntologyTerm, IOnlineReference
    {
        #region Fields
        private string _name;
        private int _recomLevel;
        private string _groupPath;
        private string _nameSpace;
        private string _defintion;
        private Uri _url;
        private string _nameSpaceAlias;
        private Dictionary<string, VariableContextSpec> _contextCollection;


        #endregion

        #region Public Properties
        private TermAttributeCollection _attributes = new TermAttributeCollection();
        public TermAttributeCollection Attributes
        {
            get
            {
                return _attributes;
            }
        }

        public Term Prototype
        {
            get { return EmitDefaultObject(false); }
        }

        public Uri URL
        {
            get { return _url; }
            set { _url = value; }
        }

        public string Definition
        {
            get { return _defintion; }
            set { _defintion = value; }
        }


        internal string NameSpace
        {
            get { return _nameSpace; }
            set { _nameSpace = value; }
        }

        internal string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
            }
        }

        //public string FqName
        //{
        //    get
        //    {
        //        StringBuilder sb = new StringBuilder();
        //        sb.AppendFormat("{0}:{1}.{2}", _nameSpace, _groupPath, _name);
        //        return sb.ToString();
        //    }
        //}



        #endregion

        #region Non Public Properties

        internal Dictionary<string, VariableContextSpec> ContextCollection
        {
            get { return _contextCollection; }
            set { _contextCollection = value; }
        }

        internal int RecommendationLevel
        {
            get
            {
                if (_attributes.Contains("RecommendationLevel"))
                    return Int16.Parse(_attributes.Find("RecommendationLevel").Value);
                else
                    return default(int);
            }
            set
            {
                if (_attributes.Contains("RecommendationLevel"))
                {
                    _attributes.Add(new TermAttribute("RecommendationLevel", value.ToString()));
                }
                else
                {
                    _attributes.Remove("RecommendationLevel");
                    _attributes.Add(new TermAttribute("RecommendationLevel", value.ToString()));
                }
            }
        }

        internal string GroupPath
        {
            get
            {
                return _groupPath;
            }
            set
            {
                _groupPath = value;
            }
        }

        internal string[] GroupLevels
        {
            get
            {
                return _groupPath.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            }
        }

        //internal string Group
        //{
        //    get
        //    {
        //        string[] t = this.GroupLevels;
        //        return t[t.Length - 1];
        //    }
        //} 
        #endregion

        public XeoTerm(string termId, string nameSpace, string nameSpaceAlias)
        {


            _supervisedObjects = new List<Term>();
            _readOnlySupervisedObjects = new ReadOnlyCollection<Term>(_supervisedObjects);
            _termId = termId;
            _nameSpace = nameSpace;
            _nameSpaceAlias = nameSpaceAlias;
            _contextCollection = new Dictionary<string, VariableContextSpec>();
            //_prototype = EmitDefaultObject(false);
        }


        #region ITermSupervisor<Parameter> Members


        public int ContextCount
        {
            get
            {
                return this._contextCollection.Count;
            }
        }

        private string _termId;
        public string TermId
        {
            get
            {

                return _termId;
            }
        }

        private List<Term> _supervisedObjects;
        private ReadOnlyCollection<Term> _readOnlySupervisedObjects;
        public IEnumerable<Term> SupervisedObjects
        {
            get { return _readOnlySupervisedObjects; }
        }


        public bool HasDefaultValue(string context)
        {
            if (this.ContextCollection.ContainsKey(context))
            {
                return !string.IsNullOrEmpty(this.ContextCollection[context].DefaultValue);
            }
            else
                throw new ArgumentException("Unknown context", context);

        }

        public bool HasDefaultCycle(string context)
        {
            if (this.ContextCollection.ContainsKey(context))
            {
                return this.ContextCollection[context].DefaultCycle != null;
            }
            else
                throw new ArgumentException("Unknown context", context);
        }



        public Term EmitDefaultObject(bool supervised)
        {

            DynamicTerm p = new DynamicTerm(_termId);
            p.Name = this.Name;
            // p.GroupPath = this.GroupPath;
            p.NameSpaceAlias = this.NameSpaceAlias;
            p.NameSpace = this.NameSpace;
            foreach (VariableContextSpec pcs in ContextCollection.Values)
            {
                if (HasDefaultCycle(pcs.Name))
                    p.Values.Add(this.DefaultCycle(pcs.Name));
                else if (HasDefaultValue(pcs.Name))
                    p.Values.Add(this.DefaultValue(pcs.Name));
            }
            if (supervised)
                Supervise(p);
            return p;
        }

        public void Supervise(Term t)
        {

            if (t.TermId == this.TermId)
            {
                if (!_supervisedObjects.Contains(t))
                {
                    _supervisedObjects.Add(t);
                    t.PropertyChanged += new PropertyChangedEventHandler(t_PropertyChanged);
                    ValidateSupervisedProperties();
                }
            }
            else
                throw new ArgumentException("TermId missmatch. Unable to supervice term", "Term");


            //if (_supervisedObject != null)
            //    _supervisedObject.PropertyChanged -= new PropertyChangedEventHandler(t_PropertyChanged);
            //_supervisedObject = t;
            //if (_supervisedObject != null)
            //{
            //    _supervisedObject.PropertyChanged += new PropertyChangedEventHandler(t_PropertyChanged);
            //    ValidateSupervisedProperties();
            //}
        }

        public void RejectSupervison(Term t)
        {
            if (_supervisedObjects.Contains(t))
            {
                _supervisedObjects.Remove(t);
                t.PropertyChanged -= new PropertyChangedEventHandler(t_PropertyChanged);
            }
        }

        void t_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            ValidateProperty(e.PropertyName);
        }

        public void ValidateSupervisedProperties()
        {
            ValidateProperty("Name");
            ValidateProperty("GroupPath");
            ValidateProperty("Values");

        }

        private void ValidateProperty(string p)
        {
            foreach (Term param in this._supervisedObjects)
            {


                switch (p)
                {
                    case "Name":
                        {
                            if (param.Name != _name)
                                OnValidation(SeverityCode.Error, "The parameter name differs from the ontology term", param);
                            break;
                        }
                    //case "GroupPath":
                    //    {
                    //        if (param.GroupPath != _groupPath)
                    //            OnValidation(SeverityCode.Error, "The parameter group path differs from the ontology term", param);
                    //        break;
                    //    }
                    case "Values":
                        {
                            //TODO
                            OnValidation(SeverityCode.Warning, "The value validation is not implemented yet.", param);

                            break;
                        }
                    default:
                        break;
                }
            }
        }

        public void PushSupervisedProperties()
        {
            foreach (Term param in _supervisedObjects)
            {
                param.Name = this.Name;

            }

        }


        private void OnValidation(SeverityCode sc, string message, Term p)
        {
            if (Validation != null)
            {
                ValidationMessage vm = new ValidationMessage(sc, message, p, false);
                Validation(this, vm);
            }
        }
        public event EventHandler<ValidationMessage> Validation;

        #endregion

        #region IParameterSupervisor Members


        internal string NameSpaceAlias
        {
            get { return _nameSpaceAlias; }
        }

        public string[] Contexts
        {
            get
            {
                string[] ret = new string[ContextCollection.Count];
                ContextCollection.Keys.CopyTo(ret, 0);
                return ret;
            }
        }

        public bool HasDefaultUnit(string context)
        {
            if (this.ContextCollection.ContainsKey(context))
            {
                VariableContextSpec pcs = this.ContextCollection[context];
                return pcs.UnitSet.DefaultUnit != null;
            }

            else
                throw new ArgumentException("Unknown context", context);
        }

        public string DefaultUnitName(string context)
        {

            if (HasDefaultUnit(context))
            {
                VariableContextSpec pcs = this.ContextCollection[context];
                return pcs.UnitSet.DefaultUnit.Name;
            }
            else
                return null;

        }

        public string DefaultUnitSymbol(string context)
        {

            if (HasDefaultUnit(context))
            {
                VariableContextSpec pcs = this.ContextCollection[context];
                return pcs.UnitSet.DefaultUnit.Symbol;
            }
            else
                return null;

        }

        public List<KeyValuePair<string, string>> ListUnits(string context)
        {
            if (this.ContextCollection.ContainsKey(context))
            {
                List<KeyValuePair<string, string>> ret = new List<KeyValuePair<string, string>>();
                VariableContextSpec pcs = this.ContextCollection[context];
                if (pcs != null)
                {
                    if (pcs.UnitSet.DefaultUnit != null)
                        ret.Add(new KeyValuePair<string, string>(pcs.UnitSet.DefaultUnit.Name, pcs.UnitSet.DefaultUnit.Symbol));
                    foreach (ConvertableUnit cu in pcs.UnitSet.ConvertableUnits)
                    {
                        ret.Add(new KeyValuePair<string, string>(cu.Name, cu.Symbol));
                    }
                }
                return ret;
            }
            else
                throw new ArgumentException("Unknown context", context);
        }

        public VariableDataTypes GetDataType(string context)
        {
            if (this.ContextCollection.ContainsKey(context))
            {
                return this.ContextCollection[context].TypeDefine.BaseType;
            }
            else
                throw new ArgumentException("Unknown context", context);


        }

        public decimal? GetMin(string context)
        {
            if (this.ContextCollection.ContainsKey(context))
            {
                Min m = this.ContextCollection[context].TypeDefine.GetMin();
                if (m != null)
                    return m.NumberVal;
                else
                    return null;
            }
            else
                throw new ArgumentException("Unknown context", context);
        }

        public decimal? GetMax(string context)
        {
            if (this.ContextCollection.ContainsKey(context))
            {
                Max m = this.ContextCollection[context].TypeDefine.GetMax();
                if (m != null)
                    return m.NumberVal;
                else
                    return null;
            }
            else
                throw new ArgumentException("Unknown context", context);
        }

        public List<KeyValuePair<string, string>> GetEnums(string context)
        {
            if (this.ContextCollection.ContainsKey(context))
            {
                List<KeyValuePair<string, string>> ret = new List<KeyValuePair<string, string>>();
                VariableContextSpec pcs = this.ContextCollection[context];
                foreach (Enum e in pcs.TypeDefine.ListEnums())
                {
                    ret.Add(new KeyValuePair<string, string>(e.TextVal, e.TextVal));
                }
                return ret;
            }
            else
                throw new ArgumentException("UnknownSample context", context);
        }


        public DynamicValue DefaultValue(string context)
        {
            return DefaultValue(context, TimeSpan.Zero);
        }

        public DynamicValue DefaultValue(string context, TimeSpan time)
        {
            if (this.ContextCollection.ContainsKey(context))
            {
                VariableContextSpec pcs = this.ContextCollection[context];
                DynamicValue v = new DynamicValue();
                v.Context = context;
                if (!string.IsNullOrEmpty(pcs.DefaultValue))
                {
                    v.Val = pcs.DefaultValue;
                }
                else
                {
                    if (HasDefaultCycle(context))
                    {
                        v.Val = (DefaultCycle(context).Values[0] as DynamicValue).Val;
                    }
                    else
                    {
                        switch (pcs.TypeDefine.BaseType)
                        {
                            case VariableDataTypes.Number:
                                {
                                    v.DoubleValue = default(double);
                                    break;
                                }
                            case VariableDataTypes.Text:
                                {
                                    v.Val = "";
                                    break;
                                }
                            case VariableDataTypes.Bool:
                                {
                                    v.BooleanValue = default(bool);
                                    break;
                                }
                            default:
                                {
                                    v.Val = "";
                                    break;
                                }
                        }
                    }
                }
                if (pcs.UnitSet.DefaultUnit != null)
                    v.Unit = pcs.UnitSet.DefaultUnit.Symbol;
                v.Time = time;
                return v;
            }
            else
                throw new ArgumentException("UnknownSample context", context);
        }


        public Cycle DefaultCycle(string context)
        {
            return DefaultCycle(context, TimeSpan.Zero);
        }
        public Cycle DefaultCycle(string context, TimeSpan time)
        {
            if (this.ContextCollection.ContainsKey(context))
            {
                VariableContextSpec pcs = this.ContextCollection[context];
                if (pcs.DefaultCycle != null)
                {

                    Cycle v = new Cycle();
                    v.Context = context;
                    foreach (KeyValuePair<TimeSpan, string> kvp in pcs.DefaultCycle)
                    {
                        v.Values.Add(new DynamicValue(kvp.Key, kvp.Value));
                    }
                    if (pcs.UnitSet.DefaultUnit != null)
                        v.Unit = pcs.UnitSet.DefaultUnit.Symbol;

                    v.Time = time;
                    return v;
                }
                else
                    return null;
            }
            else
                throw new ArgumentException("Unknown context", context);
        }

        #endregion






        ValueBase IVariableOntologyTerm.DefaultValue(string context)
        {
            return this.DefaultValue(context);
        }













        #region IOntologyTerm Members



        #endregion


    }


}
